import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzDrawerService } from 'ng-zorro-antd/drawer';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ListService, LocalizationService, TrackByService } from '@abp/ng.core';
import { SearchDropdownMenuItem } from 'joy-abpui-angular';
import { TableSettingsDialogService } from '../../core/table-settings-dialog/table-settings-dialog.service';
import { AdvancedFilterDialogService } from '../../core/advanced-filter-dialog/advanced-filter-dialog.service';
import { FilterGroupDto } from '../../proxy/joy/erp/basic-archives/core/filters/models';
import { FilterGroupRequestDto } from '../../proxy/joy/erp/basic-archives/core/filters';
import { AsnTypeDto, AsnTypeService } from '../../proxy/joy/erp/basic-archives/asns';
import { AsnTypeDawEntityComponent } from '../asn-type-daw-entity/asn-type-daw-entity.component';
import { AsnTypeConfigService } from '../config/asn-type.config';
import { ExportExcelService } from '../../core/export-excel.service';
import { debounce } from '../../core/debounce.util';

@Component({
  selector: 'lib-asn-type-list',
  templateUrl: './asn-type-list.component.html',
  styleUrls: ['./asn-type-list.component.less'],
  providers: [ListService],
})
export class AsnTypeListComponent implements OnInit {
  entityConfig;

  models: AsnTypeDto[] = [];
  selectedModels: AsnTypeDto[] = [];
  totalCount: number = 0;
  filter: string = '';
  currentFilterGroup: FilterGroupDto = null;
  searchDropdownMenuItems: SearchDropdownMenuItem[] = [
    { itemDisplayName: this.l('BasicArchives::UI:AdvancedFilterDialog.Title'), fn: this.showAdvancedSearch.bind(this) }, 
    { itemDisplayName: this.l('BasicArchives::UI:TableSettings.Title'), fn: this.showTableSettings.bind(this) }
  ];

  public get currentPage() {
    return this.listService.page + 1;
  }

  public set currentPage(page: number) {
    this.listService.page = Math.max(page - 1, 0);
  }

  public get maxResultCount() {
    return this.listService.maxResultCount;
  }

  public set maxResultCount(value: number) {
    this.listService.maxResultCount = value;
  }

  public get pageCount(): number {
    if (this.totalCount <= 0 || this.listService.maxResultCount <= 0) return 0;
    const pageCount = Math.floor(this.totalCount / this.listService.maxResultCount);
    return this.totalCount % this.listService.maxResultCount == 0 ? pageCount : pageCount + 1;
  }

  public get isAllSelected(): boolean {
    return (
      this.models.every(model => this.selectedModels.some(item => item.id === model.id)) &&
      !!this.models?.length
    );
  }
  public get indeterminate(): boolean {
    return (
      this.models.some(model => this.selectedModels.some(item => item.id == model.id)) &&
      !this.models.every(model => this.selectedModels.some(item => item.id == model.id))
    );
  }
  public get selectedCount(): number {
    return !!this.selectedModels.length ? this.selectedModels.length : 0;
  }

  isDeleteButtonDisabledFn = () => this.selectedCount <= 0;

  constructor(
    public router: Router,
    public route: ActivatedRoute,
    public readonly track: TrackByService,
    public readonly listService: ListService<FilterGroupRequestDto>,
    public drawerService: NzDrawerService,
    public modalService: NzModalService,
    public message: NzMessageService,
    public localizationService: LocalizationService,
    public entityService: AsnTypeService,
    private tableSettingsService: TableSettingsDialogService,
    private advancedFilterDialogService: AdvancedFilterDialogService,
    private asnTypeConfigService: AsnTypeConfigService,
    private exportExcelService: ExportExcelService
  ) { 
    this.entityConfig = this.asnTypeConfigService.getConfig();
  }

  ngOnInit(): void {
    this.loadTableSettings();
    this.listService.maxResultCount = 10;
    this.listService
      .hookToQuery(query => this.getListData(query))
      .subscribe(listResult => this.renderModels(listResult));
  }

  renderModels(listResult) {
    this.models = listResult.items;
    this.totalCount = listResult.totalCount;
  }

  isModelSelected(model: AsnTypeDto): boolean {
    return this.selectedModels.some(x => x.id == model.id);
  }

  @debounce()
  targetModelSelect(model: AsnTypeDto): void {
    const exists = this.selectedModels.some(item => item.id === model.id);
    if (!exists) {
      this.selectedModels = [...this.selectedModels, model];
    } else {
      this.selectedModels = this.selectedModels.filter(item => item.id !== model.id);
    }
  }

  @debounce()
  targetAllSelect(): void {
    const selectedIds = new Set(this.selectedModels.map(m => m.id));
    const allSelected = this.models.length > 0 && this.models.every(m => selectedIds.has(m.id));
    if (allSelected) {
      this.selectedModels = this.selectedModels.filter(item => !this.models.some(m => m.id === item.id));
    } else {
      const newSelected = this.models.filter(m => !selectedIds.has(m.id));
      this.selectedModels = [...this.selectedModels, ...newSelected];
    }
  }

  clearSelect() {
    this.selectedModels = [];
  }

  @debounce()
  new() {
    const drawerRef = this.drawerService.create<AsnTypeDawEntityComponent, { value: string }, string>({
      nzTitle: this.l('BasicArchives::Menu:BasicArchives.PurchasingManagement.Asns.AsnType'),
      nzContent: AsnTypeDawEntityComponent,
      nzWidth: window.innerWidth * 0.7,
      nzContentParams: {
        value: ""
      },
    });

    drawerRef.afterClose.subscribe(_ => {
      this.listService.get();
    });
  }
  
  @debounce()
  delete() {
    if (this.selectedModels.length <= 0) return;

    this.modalService.confirm({
      nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
      nzContent: this.l('BasicArchives::UI:Confirm.Content.DeleteConfirm'),
      nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
      nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
      nzOnOk: () => {
        forkJoin(
          this.selectedModels.map(model => 
            this.entityService.delete(model.id)
          )
        ).pipe(
          finalize(() => {
            this.message.success(this.l('BasicArchives::UI:Message.DeleteSuccess'));
            this.clearSelect();
            this.listService.get();
          })
        ).subscribe();
      }
    });
  }
  
  @debounce()
  refresh() {
    this.listService.get();
  }

  @debounce()
  view(model: AsnTypeDto, event?: Event) {
    event?.stopPropagation();
    
    const drawerRef = this.drawerService.create<AsnTypeDawEntityComponent>({
      nzTitle: this.l('BasicArchives::Menu:BasicArchives.PurchasingManagement.Asns.AsnType'),
      nzContent: AsnTypeDawEntityComponent,
      nzWidth: window.innerWidth * 0.7,
      nzContentParams: {
        id: model.id
      }
    });

    drawerRef.afterClose.subscribe(() => {
      this.listService.get();
    });
  }

  @debounce()
  export() {
    this.exportExcelService.exportExcel(
      this.models, 
      this.entityConfig, 
      'BasicArchives::Menu:BasicArchives.PurchasingManagement.Asns.AsnType'
    );
  }
  
  @debounce()
  search(filter: string) {
    this.filter = filter;
    this.currentFilterGroup = null;
    
    if (this.listService.page !== 0) {
      this.listService.page = 0;
    }
    
    this.clearSelect();
    this.listService.get();
  }

  @debounce()
  showAdvancedSearch() {
    const modalRef = this.advancedFilterDialogService.show(
      this.entityConfig,
      this.currentFilterGroup
    );

    modalRef.afterClose.subscribe((filterGroup: FilterGroupDto) => {
      if (filterGroup) {
        this.handleAdvancedSearchResult(filterGroup);
      }
    });
  }

  @debounce()
  showTableSettings() {
    const modalRef = this.tableSettingsService.show(this.entityConfig);

    modalRef.afterClose.subscribe((columns: any[]) => {
      if (columns) {
        // 更新所有属性
        this.entityConfig.propertys.forEach(prop => {
          const column = columns.find(c => c.name === prop.name);
          if (column) {
            prop.width = column.width;
            prop.show = column.show;
            prop.order = column.order;
            prop.fixed = column.fixed;
          }
        });

        // 排序
        this.entityConfig.propertys.sort(this.tableSettingsService.sortFunction);
        this.saveTableSettings();
      }
    });
  }

  protected loadTableSettings() {
    const savedSettings = localStorage.getItem('tableSettings::BasicArchives.Asns.AsnTypeListComponent');
    if (savedSettings) {
      const settings = JSON.parse(savedSettings);

      this.entityConfig.propertys.forEach(prop => {
        const savedProp = settings.find(s => s.name === prop.name);
        if (savedProp) {
          prop.width = savedProp.width;
          prop.show = savedProp.show;
          prop.order = savedProp.order;
          prop.fixed = savedProp.fixed;
        }
      });

      // 排序
      this.entityConfig.propertys.sort(this.tableSettingsService.sortFunction);
    }
  }

  protected saveTableSettings() {
    const settings = this.entityConfig.propertys.map(prop => ({
      name: prop.name,
      type: prop.type,
      width: prop.width,
      show: prop.show,
      order: prop.order,
      fixed: prop.fixed
    }));
    localStorage.setItem('tableSettings::BasicArchives.Asns.AsnTypeListComponent', JSON.stringify(settings));
  }

  protected getListData(query: any) {
    const baseParams = {
      maxResultCount: query.maxResultCount,
      skipCount: query.skipCount,
      sorting: query.sorting || 'CreationTime desc'
    };

    return this.filter 
      ? this.entityService.getList({
          ...baseParams,
          filter: this.filter
        })
      : this.entityService.query({
          ...baseParams,
          filterGroup: this.currentFilterGroup
        });
  }

  protected handleAdvancedSearchResult(filterGroup: FilterGroupDto) {
    this.currentFilterGroup = filterGroup;
    this.filter = '';
    
    if (this.listService.page !== 0) {
      this.listService.page = 0;
    }
    
    this.clearSelect();
    this.listService.get();
  }

  protected l(key: string, ...args: any[]): string {
    return this.localizationService.instant(key, ...args);
  }
} 